package com.sunlands.zlcx.usercenter.config;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.util.Assert;

import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

@Configuration
public class RedisConfig {
    /**
     * 注解里的字符串值必须使用字面量或者常量,所以单独定义常量, 同时用在注解和Cache定义中
     */
    public static class CacheKeys {
        private CacheKeys() {
        }

        public static final String USERS_BY_ID = "tongzhuo:users:by-id";
        public static final String USERS_BY_VERSION_TIPS = "tongzhuo:users:verion-tips";
        public static final String POSTGRADUATE_USERS_BY_VERSION_TIPS = "tongzhuo:postgraduate:users:verion-tips";
        public static final String STUDY_OPEN_DAY_ALERT_ADVERT = "tongzhuo:study:day:alert:advert";
        public static final String USERS_BY_PHONE = "tongzhuo:users:by-phone";
        public static final String USERS_BY_USERNAME = "tongzhuo:users:by-username";
        public static final String USERS_EXT_BY_USER_Id = "tongzhuo:users:ext:by-user-id";
        public static final String USERS_IN_IDS = "tongzhuo:users:in-ids";
        public static final String USERS_BLACK = "tongzhuo:users:black-users";
        public static final String USERS_ACTIVE = "tongzhuo:users:active";
        public static final String USERS_LEARN_LEAVE_MSG_SET = "tongzhuo:users:learn:set:leave-msg";
        public static final String USERS_LEARN_LEAVE_MSG_LOCK = "tongzhuo:users:learn:lock:leave-msg-task";
        public static final String REFRESH_USER_ONLINE_STATE = "tongzhuo:users:online:state:lock";
        public static final String TARGET_LIST = "target_list";
        public static final String USER_TARGET_BY_USERID = "user_target_by_userid";
        public static final String USER_STUDY_HOURS_BY_USERID = "user_study_hours_by_userid";
        public static final String APP_VERSION = "app:version";
        public static final String USER_POOL_KEY = "tongzhuo:users:user-homepage-pool";
        public static final String USER_COORDINATE = "tongzhuo:users:user-homepage-pool-coordinate";//用户获取流量池坐标key

        public static final String SET_MEAL_LIST = "tongzhuo:set-meal:list";
        public static final String SET_MEAL_BY_ID = "tongzhuo:set-meal:by-id";
        public static final String VIP_USER_INFO = "tongzhuo:vip-user:info";
        public static final String VIP_USER_LIST_INFO = "tongzhuo:vip-user:list:info";
        public static final String VIP_USER_PRIVILEGE = "tongzhuo:vip-user:privilege";
        public static final String VIP_USER_CONTROL_LOCK = "tongzhuo:vip-user:lock:control";
        public static final String VIP_USER_REFRESH_LOCK = "tongzhuo:vip-user:lock:refresh";
        public static final String VIP_USER_VIP_STATUS_LOCK = "tongzhuo:vip-user:lock:user-vip-status";
        public static final String VIP_USER_END_NOTICE_LOCK = "tongzhuo:vip-user:lock:end-notice";
        public static final String VIP_USER_CHARGING_LEAVE = "tongzhuo:vip-user:charging:leave";
        public static final String VIP_TIME_PRE_CHARGING = "tongzhuo:vip-time:lock:pre-charging";

        public static final String USERS_INVITE_RULE = "tongzhuo:users:invite:rule";
        public static final String USERS_INVITE_CODE_LIST = "tongzhuo:users:invite:code:list";
        public static final String USERS_INVITE_CODE_COUNT = "tongzhuo:users:invite-code:count";

        public static final String USERS_LEARN_CONTENT_LIST = "tongzhuo:learn:content:list";
        public static final String USERS_LEARN_ALL_CONTENT_LIST = "tongzhuo:learn:content:all:list";
        public static final String USERS_LEARN_CONTENT_BY_ID = "tongzhuo:learn:content:by-id";

        public static final String CITY_LIST = "tongzhuo:users:city-list";
        public static final String SCHOOL_LIST = "tongzhuo:users:school-list";
    }

    /**
     * 这里记录cache key和过期时间
     */
    private enum CacheEnum {

        /**
         *
         */
        SCHOOL_LIST(CacheKeys.SCHOOL_LIST, 60 * 60 * 24),
        USERS_IN_IDS(CacheKeys.USERS_IN_IDS, 60),
        USERS_ACTIVE(CacheKeys.USERS_ACTIVE, 60 * 60 * 24),
        USERS_BLACK(CacheKeys.USERS_BLACK, 2 * 60),
        APP_VERSION(CacheKeys.APP_VERSION, 5 * 60),
        USERS_LEARN_ALL_CONTENT_LIST(CacheKeys.USERS_LEARN_ALL_CONTENT_LIST, 60 * 60),
        ;

        public final String cacheName;
        public final int expireInSeconds;

        CacheEnum(String cacheName, int expireInSeconds) {
            this.cacheName = cacheName;
            this.expireInSeconds = expireInSeconds;
        }
    }
    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        cacheManager.setUsePrefix(true);
        //缓存默认60秒, 如果特别情况在CacheEnum里设置
        cacheManager.setDefaultExpiration(60);

        Map<String, Long> expires = Arrays.stream(RedisConfig.CacheEnum.values())
                .collect(Collectors.toMap(e -> e.cacheName, e -> Long.valueOf(e.expireInSeconds)));

        cacheManager.setExpires(expires);
        return cacheManager;
    }

    /**
     * 存入对象tostring后的信息
     *
     * @return RedisTemplate
     */
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
                ObjectMapper objectMapper = new ObjectMapper()
                .findAndRegisterModules()
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

        RedisTemplate<String, ?> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer
                = new GenericJackson2JsonRedisSerializer(objectMapper);

        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);

        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        return redisTemplate;
    }

    static class StringRedisSerializer implements RedisSerializer<Object>{
        private final Charset charset;

        public StringRedisSerializer() {
            this(Charset.forName("UTF8"));
        }

        public StringRedisSerializer(Charset charset) {
            Assert.notNull(charset, "Charset must not be null!");
            this.charset = charset;
        }
        @Override
        public String deserialize(byte[] bytes) {
            return (bytes == null ? null : new String(bytes, charset));
        }
        @Override
        public byte[] serialize(Object object) {
            return (object == null ? null : object.toString().getBytes(charset));
        }
    }

}
